package com.e3.web.core.server;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;

import com.e3.core.base.SessionContext;
import com.e3.core.utils.ConfigFileReader;
import com.e3.web.login.server.LoginHelper;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.RPC;
import com.google.gwt.user.server.rpc.RPCRequest;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * 所有的rpc servlet调用都将由该servlet转发。 该类中会统一设置当前登录用户的信息，并维护好ThreadLocal的公共信息。
 * 
 * @author Administrator
 * 
 */
public class GWTServiceServlet extends RemoteServiceServlet {
	private static final long serialVersionUID = -747201361831841995L;

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		String path = config.getServletContext().getRealPath("/");
		ConfigFileReader.setWebRoot(path);
	}

	@Override
	public String processCall(String payload) throws SerializationException {
		String url = getThreadLocalRequest().getRequestURL().toString();
		String serviceName = url.substring(url.lastIndexOf("/") + 1);
		GwtRPCAction serviceHandler = GwtRPCActionConfig.getRPCServletClass(serviceName);
		serviceHandler.setThreadLocalRequest(this.getThreadLocalRequest());
		serviceHandler.setThreadLocalResponse(this.getThreadLocalResponse());
		try {
			RPCRequest rpcRequest = RPC.decodeRequest(payload,serviceHandler.getClass(), this);
			if(!beforeInvokeAndResponse(rpcRequest,serviceName)){
				return "";
			}
			return RPC.invokeAndEncodeResponse(serviceHandler,rpcRequest.getMethod(), rpcRequest.getParameters(),
					rpcRequest.getSerializationPolicy());
		} catch (IncompatibleRemoteServiceException ex) {
			getServletContext()
					.log("An IncompatibleRemoteServiceException was thrown while processing this call.",ex);
			return RPC.encodeResponseForFailure(null, ex);
		}
	}

	@Override
	protected void onAfterResponseSerialized(String serializedResponse) {
		SessionContext.remove();
	}
	
	private boolean beforeInvokeAndResponse(RPCRequest rpcRequest,String serviceName){
		if("ResourceRPCService".equals(serviceName)){
			String mName = rpcRequest.getMethod().getName();
			if("getClientSession".equals(mName)){
				Boolean isDeveloping = (Boolean)rpcRequest.getParameters()[0];
				SessionContext.setDeveloping(isDeveloping);
			}
		}
		
		if(SessionContext.isDeveloping()){
			return true;
		}
		if (!LoginHelper.isLogined(getThreadLocalRequest())) {
			throw new UnloginException();
		}
		SessionContext.setSession(LoginHelper.getSession(getThreadLocalRequest()));
		return true;
	}

	@Override
	protected void onBeforeRequestDeserialized(String serializedRequest) {

	}

	private void forwardToLogin() {
		try {
			LoginHelper.gotoLogin(getThreadLocalRequest(),getThreadLocalResponse());
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ServletException e) {
			e.printStackTrace();
		}
//
//		getThreadLocalResponse().setContentType("text/plain");
//		getThreadLocalResponse().setStatus(HttpServletResponse.SC_UNAUTHORIZED);
//		try {
//			getThreadLocalResponse().getWriter().write("");
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
	}

	@Override
	protected void doUnexpectedFailure(Throwable e) {
		SessionContext.remove();
		if(e instanceof UnloginException){
			forwardToLogin();
			return;
		}
		super.doUnexpectedFailure(e);
	}

}
